#include "base64.hpp"

std::string base64::encode(const std::vector<uint8_t>& in)
{
	std::string out;

	unsigned val = 0;
	int valb = -6;
	for (auto c : in) {
		val = (val << 8) + c;
		valb += 8;
		while (valb >= 0) {
			out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]);
			valb -= 6;
		}
	}
	if (valb > -6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]);
	while (out.size() % 4) out.push_back('=');
	return out;
}

std::vector<uint8_t> base64::decode(const std::string& in)
{
	std::vector<uint8_t> out;
	out.reserve(8 * (1 + in.size() / 6));

	std::vector<int> T(256, -1);
	for (int i = 0; i < 64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;

	unsigned val = 0;
	int valb = -8;
	for (auto c : in)
	{
		if (T[c] == -1) break;
		val = (val << 6) + T[c];
		valb += 6;
		if (valb >= 0)
		{
			out.push_back(uint8_t((val >> valb) & 0xFF));
			valb -= 8;
		}
	}
	return out;
}
